﻿//#define OPEN_EDITOR

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;

public class AssetBundler
{
    static Dictionary<string, string> existList = new Dictionary<string, string>();
    static List<object[]> packList = new List<object[]>();
    static Dictionary<string, string[]> AssetDepList = new Dictionary<string,string[]>();

#if OPEN_EDITOR
    [MenuItem("Assets/Unpack Asset")]
#endif
    static void UnpackAsset()
    {
        existList.Clear();
        foreach (Object obj in Selection.objects)
        {
            UnpackAsset(obj);
        }
    }

    static Dictionary<string, int> depSortList = new Dictionary<string, int>();
    static public int CompDepList(string x, string y)
    {
        return depSortList[x] < depSortList[y] ? -1 : 1;
    }

    public static string[] SortList(string[] list)
    {
        if (list.Length <= 0)
            return list;

        List<string> ss = new List<string>(list);
        ss.Sort(CompDepList);
        return ss.ToArray();
    }

    public static void UnpackObjects(List<Object> objs)
    {
        packList.Clear();
        existList.Clear();
        AssetDepList.Clear();
        depSortList.Clear();
        int num = 0;
        foreach (Object obj in objs)
        {
            UnpackAssetDependencies(obj, ref num);
        }

        string ssss = "";
        //Dictionary<Object, bool> DDDD = new Dictionary<Object, bool>();
        int depnum = 0;
        bool bSet = false;
        BuildPipeline.PushAssetDependencies();
        ssss += "BuildPipeline.PushAssetDependencies();\n\r";
        for (int i = 0; i < packList.Count; ++i)
        {
//            BuildPipeline.PushAssetDependencies();
//             if (DDDD.ContainsKey((UnityEngine.Object)packList[i][0]))
//             {
//                 Logger.LogError("DepAlread:{0}", AssetDatabase.GetAssetPath((UnityEngine.Object)packList[i][0]));
//             }
//             else
//             {
//                 DDDD[(UnityEngine.Object)packList[i][0]] = true;
//             }

            if ((BuildAssetBundleOptions)packList[i][2] != BuildAssetBundleOptions.DeterministicAssetBundle)
            {
                if (bSet == false)
                {
                    bSet = true;
                }
                else
                {
                    BuildPipeline.PushAssetDependencies();
                    ssss += "BuildPipeline.PushAssetDependencies();\n\r";
                    depnum++;
                }
            }
            else
            {
                Debug.LogWarning("No PushAssetDependencies");
            }

            ssss += string.Format("BuildPipeline.BuildAssetBundle({0}, {1});\n\r", (string)packList[i][1], (BuildAssetBundleOptions)packList[i][2]);
            UnityEditor.BuildPipeline.BuildAssetBundle((UnityEngine.Object)packList[i][0], null, (string)packList[i][1], (BuildAssetBundleOptions)packList[i][2], GetBuildTarget());
        }

        for (int i = 0; i < depnum; ++i)
        {
            ssss += "BuildPipeline.PopAssetDependencies();\n\r";
            BuildPipeline.PopAssetDependencies();
        }
        ssss += "BuildPipeline.PopAssetDependencies();";
        BuildPipeline.PopAssetDependencies();
        StreamWriter Write = new StreamWriter(Application.dataPath + "/../Data/AssetBundler.txt", false, System.Text.Encoding.UTF8);
        Write.Write(ssss);
        Write.Close();

        Dictionary<string, string[]> tmpList = new Dictionary<string, string[]>();
        foreach (KeyValuePair<string, string[]> itor in AssetDepList)
        {
            tmpList[itor.Key] = SortList(itor.Value);
        }

        AssetDepList = tmpList;
        AssetsDepHandler.UpdateToFile(AssetDepList, assetFilePath + "AssetsDependencies.XML");

        packList.Clear();
    }

#if OPEN_EDITOR
    [MenuItem("Assets/Unpack Asset Dep")]
#endif
    static void UnpackAssetDep()
    {
        UnpackObjects(new List<Object>(Selection.objects));
    }

    //public static BuildAssetBundleOptions options = BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets | BuildAssetBundleOptions.DeterministicAssetBundle/* | BuildAssetBundleOptions.UncompressedAssetBundle*/;
    public static BuildAssetBundleOptions options = BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.DeterministicAssetBundle | BuildAssetBundleOptions.DisableWriteTypeTree;
    static string assetFilePath = ResourcesPath.LocalPath;
    static string configFilePath = ResourcesPath.LocalConfigPath;
    static string SwitchPath(string path)
    {
        //Debug.Log(path);
        string s = path.Substring(7);
        s = s.Replace('.', '_');
        s += "_Dep.assetbunld";
        return s;
    }
    static void AddDep(string asset, string[] deps)
    {
        List<string> deplist = new List<string>();
        for (int i = 0; i < deps.Length; ++i)
        {
            if (asset != deps[i])
            {
                if (!deps[i].EndsWith(".cs") && !deps[i].EndsWith(".js"))
                    deplist.Add(SwitchPath(deps[i]));
            }
        }

        AssetDepList[SwitchPath(asset)] = deplist.ToArray();
    }

    // 地图数据根据依赖关系打包，在PC平台是正常的，但是在安卓平台，地形显示不正常，所以，地图数据不根据依赖打包
    static string[] GetDependencies(Object obj)
    {
//         if (obj as TerrainData)
//             return new string[0];

//         List<string> exps = null;
//         if (obj as GameObject)
//         {
//             GameObject go = (GameObject)obj;
//             Terrain terrain;
//             if ((terrain = go.GetComponent<Terrain>()) != null)
//             {
//                 if (terrain.terrainData != null)
//                 {
//                     exps = new List<string>(AssetDatabase.GetDependencies(new string[1] { AssetDatabase.GetAssetPath(terrain.terrainData) }));
//                 }
//             }
//         }

        List<string> deps = new List<string>(AssetDatabase.GetDependencies(new string[1] { AssetDatabase.GetAssetPath(obj) }));
//         if (exps != null)
//         {
//             for (int i = 0; i < exps.Count; ++i)
//             {
//                 deps.Remove(exps[i]);
//             }
//         }

//         for (int i = 0; i < deps.Count;)
//         {
//             if (deps[i].EndsWith(".cs") || deps[i].EndsWith(".js"))
//             {
//                 deps.RemoveAt(i);
//             }
//             else
//             {
//                 ++i;
//             }
//         }

        return deps.ToArray();
    }

    static void UnpackAssetDependencies(Object obj, ref int num)
    {
        string path = AssetDatabase.GetAssetPath(obj);
        string[] depends;
        depends = GetDependencies(obj);

        AddDep(path, depends);
        int depNum = 0;
        BuildAssetBundleOptions op = BuildAssetBundleOptions.DeterministicAssetBundle;
        for (int i = 0; i < depends.Length; ++i)
        {
            if (path != depends[i])
            {
                if (!depends[i].EndsWith(".cs") && !depends[i].EndsWith(".js"))
                {
                    depNum++;
                    UnpackAssetDependencies(AssetDatabase.LoadAssetAtPath(depends[i], typeof(Object)), ref num);
                    op |= BuildAssetBundleOptions.CollectDependencies;
                }
                else
                {
                    op |= BuildAssetBundleOptions.CompleteAssets | BuildAssetBundleOptions.CollectDependencies;
                }
            }
        }

        string savePath = assetFilePath + path.Substring(7, path.Length - 7);
        //Logger.LogDebug("savePath:{0}", savePath);
        Directory.CreateDirectory(savePath.Substring(0, savePath.LastIndexOf('/')));
        savePath = path.Substring(7, path.Length - 7);
        savePath = savePath.Replace('.', '_');
        savePath += "_Dep.assetbunld";
        savePath = assetFilePath + savePath;
        if (!existList.ContainsKey(path))
        {
            depSortList.Add(SwitchPath(path), depSortList.Count);
            existList.Add(path, savePath);
            packList.Add(new object[3] { obj, savePath, op });
        }
    }

    public static string GetSavePath(Object o)
    {
        string path = AssetDatabase.GetAssetPath(o);
        string savePath = path.Substring(7, path.Length - 7);
        savePath = savePath.Replace('.', '_');
        savePath += "_Dep.assetbunld";
        return savePath;
    }

    static void UnpackAsset(Object obj)
    {
        string path = AssetDatabase.GetAssetPath(obj);
        string savePath = assetFilePath + path.Substring(7, path.Length - 7);
        Directory.CreateDirectory(savePath.Substring(0, savePath.LastIndexOf('/')));
        savePath = savePath.Substring(0, savePath.LastIndexOf('.'));
        savePath += ".assetbunld";
        UnityEditor.BuildPipeline.BuildAssetBundle(obj, null, savePath, BuildAssetBundleOptions.CollectDependencies, GetBuildTarget());
    }

    public static BuildTarget GetBuildTarget()
    {
#if UNITY_IPHONE
        return BuildTarget.IPHONE;
#endif
#if UNITY_ANDROID
        return BuildTarget.Android;
#endif
#if UNITY_STANDALONE_WIN
        return BuildTarget.StandaloneWindows;
#endif
    }
}
